#ifndef STATE_MACHINE_H
#define STATE_MACHINE_H

#include "State.h"

// in case NULL is not defined
#ifndef NULL
#define NULL 0
#endif

template <class entity_type>
class StateMachine {
public:
//---- Constructor ----//
	StateMachine(entity_type* p_owner): 
		m_owner(p_owner),
		m_currentState(NULL),
		m_previousState(NULL),
		m_globalState(NULL)
	{}


//---- state manipulation ----//
	void setCurrentState(State<entity_type>* p_state) {
		m_currentState = p_state;
	}

	void setPreviousState(State<entity_type>* p_state) {
		m_previousState = p_state;
	}

	void setGlobalState(State<entity_type>* p_state) {
		m_globalState = p_state;
	}

	void changeState(State<entity_type>* p_newState) {
		m_previousState = m_currentState;
		m_currentState->exit(m_owner);
		m_currentState = p_newState;
		m_currentState->enter(m_owner);
	}

	void revertToPreviousState() {
		changeState(m_previousState);
	}



//---- message handler ----//
	bool handleMessage(const Telegram& msg) const {
		if(m_currentState && m_currentState->onMessage(m_owner, msg)) {
			return true;
		}

		if(m_globalState && m_globalState->onMessage(m_owner, msg)) {
			return true;
		}

		return false;
	}

    
    
//---- Update function ----//
	void update() const {
		if(m_globalState) {
			m_globalState->execute(m_owner);
		}

		if(m_currentState) {
			m_currentState->execute(m_owner);
		}
	}



//---- Accessors ----//
	State<entity_type>* getCurrentState() const {
		return m_currentState;
	}

	State<entity_type>* getPreviousState() const {
		return m_previousState;
	}

	State<entity_type>* getGlobalState() const {
		return m_globalState;
	}


	bool isInState(const State<entity_type>& st)const {
		if (typeid(*m_pCurrentState) == typeid(st)) return true;
		return false;
	}



private:
	entity_type* m_owner;

	State<entity_type>* m_currentState;

	State<entity_type>* m_previousState;

	State<entity_type>* m_globalState;
};

#endif